#include "song_manip.h"



typedef enum {INACTIVE, PLAY, PAUSE, STOPPED} MUSIC_STATE;
volatile MUSIC_STATE state = PLAY;
volatile int ms_count = 0;
int song_note_ind = 0;

void rtc_isr(void)
{
	Byte cause = read_rtc(RTC_STAT_C);
	
	if(cause & RTC_PF) // periodic interrupt
	{
		switch(state)
		{
			case INACTIVE:
				break;

			case STOPPED:
				if(!isEmptyGQueue(music_queue))
				{
					Note* nt = (Note*)getGQueue(music_queue);
					if(nt->freq != PAUSE_FREQ)
					{
						timer_load(TIMER_2, get_divider(notes_frequency[nt->freq]));
						speaker_on();
					}
					ms_count = nt->dur;
					state = PLAY;
				}
				break;
				
			case PLAY:
				if(ms_count-- == 0)
				{
					speaker_off();
					//ms_count = 20;
					ms_count = bgm->pause;
					state = PAUSE;
					if(song_note_ind < bgm->lenght)
						putGQueue(music_queue, &(bgm->notes[song_note_ind++]));
				}
				break;
				
			case PAUSE:
				if(ms_count-- == 0)
					state = STOPPED;
				break;
		}
	}
	
	outportb(PIC1_CMD, EOI);
	outportb(PIC2_CMD, EOI);
}


void load_notes_queue()
{	
	Note k;
	k.freq=Do4;
	k.dur = 2000;
	putGQueue(music_queue, &k);
	k.freq=Si4;
	k.dur = 2000;
	putGQueue(music_queue, &k);
}


void song_pre_load_queue(int n_notes)
{
	for(song_note_ind = 0; song_note_ind < n_notes; song_note_ind++)
		putGQueue(music_queue, &(bgm->notes[song_note_ind]));
}


void song_init(char* songname)
{
	music_queue = newGQueue(10, sizeof(Note));
	//load_notes_queue();
	state = STOPPED;
	bgm = song_load(songname);
	song_pre_load_queue(3);
	
	//timer_init(2, LCOM_MODE);
	install_c_irq_handler(RTC_IRQ, rtc_isr, &old_rtc_irq);
	rtc_int_enable();
}


void song_finalize()
{
	speaker_off();
	state = INACTIVE;
	
	rtc_int_disable();
	reinstall_c_irq_handler(RTC_IRQ, &old_rtc_irq);
	
	song_delete(bgm);
	deleteGQueue(music_queue);
}

Song* song_load(char* filename)
{
	FILE* pFile;
	pFile = fopen(filename, "r");
	if(!pFile) return NULL;
	
	int beats_measure, n_notes; float bpm;
	fscanf(pFile, "%i %f %i\n", &beats_measure, &bpm, &n_notes);
	
	Note* nt = malloc(n_notes * sizeof(Note));
	if(!nt) return NULL;
	
	Song* s = malloc(sizeof(Song));
	if(!s)
	{
		free(nt);
		return NULL;
	}
	
	s->lenght = n_notes; s->pause = 0; s->notes = nt;
	
	int i;
	for(i = 0; i < n_notes; i++)
		fscanf(pFile, "%i %i\n", &(s->notes[i].freq), &(s->notes[i].dur));
	
	if(beats_measure != -1)
		set_bpm(s, beats_measure, bpm);
	
	fclose(pFile);
	return s;
}


void set_bpm(Song* s, int beats_measure, float bpm)
{
	//(beats_measure / 4) esta para (60000ms / bpm) assim como 1 esta para multiplier
	float multiplier = 240000.0 / (beats_measure * bpm);
	
	int i;
	for(i = 0; i < s->lenght; i++)
		(s->notes)[i].dur *= multiplier;
}


void modify_bpm(Song* s, float old_bpm, float new_bpm)
{
	float multiplier = old_bpm / new_bpm;
	int i;
	for(i = 0; i < s->lenght; i++)
		(s->notes)[i].dur *= multiplier;
}


void modify_pitch(Song* s, int halfsteps_up)
{
	int i;
	for(i = 0; i < s->lenght; i++)
		if((s->notes)[i].freq != PAUSE_FREQ)
			(s->notes)[i].freq += halfsteps_up;
}


void song_save(Song* s, char* filename)
{
	FILE* pFile;
	pFile = fopen(filename, "w");
	if(!pFile) return;
	
	fprintf(pFile, "-1 0.0 %i\n", s->lenght);
	
	int i;
	for(i = 0; i < s->lenght; i++)
		fprintf(pFile, "%i %i\n", s->notes[i].freq, s->notes[i].dur);
	
	fclose(pFile);
}


void song_delete(Song* s)
{
	free(s->notes);
	free(s);
}
